package org.zhuzx.util;

import java.util.*;
import java.util.concurrent.*;

/**
 * 可自清理缓存
 * @author	zhuzx	2016年9月25日
 */
public class SelfCleaningCache {
	
	private static final long CHECKING_PERIOD = 1000L * 60 * 10;
	private static final long RETENTION_TIME = CHECKING_PERIOD * 6;
	private static final TimingHashMap<String,Object> cache = new TimingHashMap<String,Object>();
	
	static {
		class Cleaner implements Runnable {
			public void run() {
				long currentTime = System.currentTimeMillis();
				Iterator<String> ite = cache.keySet().iterator();
				while (ite.hasNext()) {
					String key = ite.next();
					long addedTime = cache.getTimestamp(key);
					if (currentTime-addedTime >= RETENTION_TIME) {
						ite.remove();
//						System.out.println(">>>>SelfCleaningCache remove: " + key);
					}
				}
			}
		};
		ConcurrentUtil.scheduleAtFixedRate(new Cleaner(), 0, CHECKING_PERIOD);
	}
	
	public static Object put(String key, Object value) {
//		System.out.println(">>>>SelfCleaningCache add: " + key);
		return cache.put(key, value);
	}
	
	public static Object get(String key) {
		return cache.getAndProlong(key);
	}
	
	@Deprecated//重定义TimingHashMap，按访问时间实时排序，以便清理线程提前结束迭代。LinkedHashMap可以使用LRU模式，但无并发优势。
	private static class TimingHashMap<K,V> extends ConcurrentHashMap<K,V>{
		private static final long serialVersionUID = 5510178495506659401L;
		private Map<K,Long> timing;
		public TimingHashMap() {
			super();
			timing = new ConcurrentHashMap<K,Long>();
		}
		public V put(K key, V value) {
			timing.put(key, System.currentTimeMillis());
			return super.put(key, value);
		}
		public V getAndProlong(K key) {
			V value = super.get(key);
			if (value != null) {
				timing.put(key, System.currentTimeMillis());
			}
			return value;
		}
		public Long getTimestamp(K key) {
			return timing.get(key);
		}
	}
	
	public static void main(String[] args) {
		class TestCache implements Runnable {
			int count = 1;
			public void run() {
				SelfCleaningCache.put(String.valueOf(count), "value");
				System.out.println(cache);
				count++;
			}
		};
		ConcurrentUtil.scheduleAtFixedRate(new TestCache(), 0, CHECKING_PERIOD/6);
	}
	
}